#! /usr/bin/env python

import sys
import os
import tempfile
import getopt
import subprocess
import shlex
import re
import shutil
import platform
import random
import platform
import autotagshows
import iphoneencodegui


GLOBALPARAM = {}
GLOBALPARAM['version']="1.0"

if sys.version_info > (3, 0):
	def execfile(filename):
		exec(compile(open(filename).read(), filename, 'exec'))

def initfileparam(file):
	fp={}
	fp['path']=file
	fp['DESTDIR']=GLOBALPARAM['DESTDIR']
	fp['FINALDIR']=GLOBALPARAM['FINALDIR']
	fp['DEVICECONFS']=GLOBALPARAM['DEVICECONFS']
	fp['CHECKDB']=GLOBALPARAM['CHECKDB']

	GLOBALPARAM['TMPC']=GLOBALPARAM['TMPC']+1
	fp['TMP']=GLOBALPARAM['TMP']+str(GLOBALPARAM['TMPC'])
	return fp

def globalparamdef():
	GLOBALPARAM['PATHDEF']=os.path.dirname(os.path.abspath(sys.argv[0]))+os.sep
	GLOBALPARAM['TMP']=tempfile.mkdtemp("iphonencode")+os.sep
	GLOBALPARAM['TMPC']=0

	GLOBALPARAM['VERBOSE']=False
	GLOBALPARAM['NOGUI']=False

	GLOBALPARAM['USERPARAM']=""
	GLOBALPARAM['INTERACT']=True
	GLOBALPARAM['SHORT']=""
	GLOBALPARAM['CHECKDB']=False
	GLOBALPARAM['NOTAG']=False

	GLOBALPARAM['DESTDIR']=""
	GLOBALPARAM['FINALDIR']=""
	GLOBALPARAM['DEVICECONFS']=1 # 1: ipad, 2: iphone3G, 3:both
	GLOBALPARAM['SHOWPREFS']=True

	GLOBALPARAM['mplayer']="mplayer"
	GLOBALPARAM['mencoder']="mencoder"
	GLOBALPARAM['MP4Box']="MP4Box"


	if os.path.basename(sys.argv[0]) == "iphoneencodeauto":
		print( "Default settings to auto add to iTunes")
		GLOBALPARAM['FINALDIR']="/home/genovch/iphonencode/Automatically Add to iTunes/"
		GLOBALPARAM['DESTDIR']="/home/genovch/iphonencode/temp"
		GLOBALPARAM['CHECKDB']=True

	# read config file 
	if os.path.exists(GLOBALPARAM['PATHDEF']+"config.txt"):
		try:
			execfile(GLOBALPARAM['PATHDEF']+"config.txt")
		except SystemExit as err:
			print("error parsing config file "+str(err))
			sys.exit(2)

def getGlobalParam(newval=None):
	global GLOBALPARAM
	if newval == None:
		return GLOBALPARAM
	else:
		GLOBALPARAM=newval

def usage():
	print( """
	iphoneencode script 1.0, written by Christope "KrisT@uF" Genova
	usage
	iphoneencode [options] file1 file2 file3 ...
	options:
		--verbose	verbose mode
		--nogui		do not open gui
		--todir=dir	to move results to dir [default is in same directory]
		--ipad 		Optimize transcode for iPad and iPhone4 (HD)
		--iphone	Optimiez transcode for iPhone 1,3G, 3GS (SD)
		--sdhd		Generate both --ipad and --iphone with same cnID (it will be seen as only one file in iTunes)
		--short		Transcode only a short part for testing purpose
		--nointeract	do not ask for missing ID
		--checkdb	do not transcode file if DB file is present (--nocheckdb to prevent it)	
		--notag		do not try to tag (no web access)
	
"""	)

def analyzearg(argv):
	try:
		opts, args = getopt.getopt(argv, "",["verbose", "todir=", "ipad", "iphone", "sdhd", "iboth", "param=", "short", "nointeract", "checkdb", "nocheckdb", "notag", "nogui"])
	except getopt.GetoptError:           
		usage()                          
		sys.exit(2)   

	for opt, arg in opts:
		if opt == "--verbose":
			GLOBALPARAM['VERBOSE']=True
		
		if opt == "--nogui":
			GLOBALPARAM['NOGUI']=True

		if opt == "--todir":
			GLOBALPARAM['DESTDIR']=arg

		if opt == "--ipad":
			GLOBALPARAM['DEVICECONFS']=[ "ipad" ]
		if opt == "--iphone":
			GLOBALPARAM['DEVICECONFS']=[ "iphone" ]
		if opt == "--ipadcopy":
			GLOBALPARAM['DEVICECONFS']=[ "ipadcopy" ]
		if opt == "--sdhd" or opt == "--iboth":
			GLOBALPARAM['DEVICECONFS']=[ "ipad", "iphone" ]

		if opt == "--short":
			GLOBALPARAM['SHORT']="-ss 00:10:00 -endpos 0:00:10"

		if opt == "--nointeract":
			GLOBALPARAM['INTERACT']=False

		if opt == "--checkdb":
			GLOBALPARAM['CHECKDB']=True
		
		if opt == "--nocheckdb":
			GLOBALPARAM['CHECKDB']=False
		
		if opt == "--notag":
			GLOBALPARAM['NOTAG']=True
		
		""" non official option """
		if opt == "--param":
			GLOBALPARAM['USERPARAM']=arg.replace("_"," ")
			print( "Using user param " + GLOBALPARAM['USERPARAM'])
	
	if not GLOBALPARAM['NOGUI']:
		GLOBALPARAM['VERBOSE']=True

	return args

def externalcall(cmd, progressstyle='None',outputmode='Print',exit=True,progressmsg=""):
	regexcmd=""
	if GLOBALPARAM['VERBOSE']:
		iphoneencodegui.log( "Calling "+cmd)
	if progressstyle != 'None':
		if progressstyle == 'mencoder':
			regexcmd="([0-9]*)%"
		elif progressstyle == 'MP4Box':
			regexcmd="([0-9]*)/"
		else:
			progressstyle='None'
	if progressstyle == 'None':
		unewl=False
	else:
 		unewl=True

	iphoneencodegui.progress(0,msg=progressmsg)
	CREATE_NO_WINDOW = 0x8000000
	try:
		if platform.system() == "Windows":
			pipe = subprocess.Popen( shlex.split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=unewl, bufsize=1,creationflags=CREATE_NO_WINDOW)
		else:
			pipe = subprocess.Popen( shlex.split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=unewl, bufsize=1)
	except Exception, e:
		iphoneencodegui.log(e,True)

	if outputmode == 'Print':
		out=False
		if progressstyle == 'None':
			for l in pipe.stdout:
				if iphoneencodegui.needToStop():
					pipe.kill()
					return True
				iphoneencodegui.log(str(l).rstrip("\n"))
		else:
			prevprogress=""
			iphoneencodegui.log("")
			while True:
				if iphoneencodegui.needToStop():
					pipe.kill()
					return True
				l=pipe.stdout.readline()
				if len(l) == 0:
					break
				if GLOBALPARAM['VERBOSE']:
					iphoneencodegui.log(str(l).rstrip("\n"))
				progress=re.search(regexcmd,l)
				if progress != None and progress.group(1) != prevprogress:
					iphoneencodegui.progress(progress.group(1))
					prevprogress=progress.group(1)
		iphoneencodegui.log("")
	elif outputmode == 'Dump':
		out=[]
		for l in pipe.stdout:
			if iphoneencodegui.needToStop():
				pipe.kill()
				return True
			out.append(l)
	else:
		out=False

	if  pipe.wait() != 0:
		msg="Error calling "+str(cmd)+"\n\n"
		for l in pipe.stderr:
			msg=msg+str(l)
		iphoneencodegui.log(msg,True)
		out=True
		if exit:
			sys.exit(2)   
	iphoneencodegui.progress(100)
	return out

def getvideoinfo(fp,name=""):
	if name == "":
		name=fp['path']
	dict=[ ['ID_VIDEO_FPS=([0-9.]*)', 'fps' ], ['ID_VIDEO_WIDTH=([0-9]*)', 'width'], ['ID_VIDEO_HEIGHT=([0-9]*)', 'height']]
	cmd="\""+GLOBALPARAM['mplayer']+"\" -endpos 0:00:02 -quiet -identify -nosound -vo text " + GLOBALPARAM['USERPARAM']+ " \"" + name +"\""
	mplayerout=externalcall(cmd,outputmode='Dump')
	found=0
	for l in mplayerout:
		for d,i in dict:
			reg=re.search(d,str(l))
			if reg != None:
				fp[i]=float(reg.group(1))
				found=found+1
	if found != len(dict):
		iphoneencodegui.log("Error parsing video file "+name,True)
		sys.exit(2)
	if GLOBALPARAM['VERBOSE']:
		iphoneencodegui.log( "Video "+str(fp['width'])+"x"+str(fp['height'])+" at "+str(fp['fps'])+" fps")

def setfilevar(fp):
	fp['dir']=os.path.dirname(os.path.abspath(fp['path']))
	fp['name']=os.path.basename(fp['path'])
	fp['noext']=os.path.splitext(fp['name'])[0]
	fp['noextclean']=fp['noext']

	fp['msg']="Encoding "+fp['path']

	fp['subfile']=""
	fp['subcmd']=""
	if os.path.exists(fp['dir']+"/"+fp['noext']+".srt"):
		fp['subfile']=fp['dir'] + "/" + fp['noext']+ ".srt"
		fp['msg']=fp['msg']+" with subtitle " + fp['subfile']
		fp['subcmd']="-noautosub -sid 666"


	if fp['DESTDIR'] == "":
		fp['DESTDIR']=fp['dir']
	fp['noext']=fp['noext'] + "_for_" + fp['DEVICECONF']
	fp['dest']=fp['DESTDIR']+"/"+fp['noext']+".m4v"
	if fp['FINALDIR'] != "":
		fp['finaldest']=fp['FINALDIR']+"/"+fp['noext']+".m4v"
	else:
		fp['finaldest']=fp['dest']
	fp['msg']=fp['msg']+" to "+fp['finaldest']

	getvideoinfo(fp)
	if fp['fps'] < 24:
		iphoneencodegui.log("Correct fps because detected fps is "+str(fp['fps']))
		fp['fps']=24
		fp['FPSCMD']="-ofps 24000/1001"
	else:
		fp['FPSCMD']=""

	return fp


def encodefile(fp):
	iphoneencodegui.log( fp['msg'])

	if os.path.exists(fp['finaldest']):
		iphoneencodegui.log( "Output file "+fp['finaldest']+ " exists already!", True)
		return True
	if fp['CHECKDB'] and os.path.exists(fp['dir']+"/"+fp['noextclean']+".DB.Info"):
		iphoneencodegui.log( "DB file "+fp['dir']+"/"+fp['noextclean']+".DB.Info exists, do not transcode" )
		return True
	else:
		fp['CHECKDB']=False #check only for first deviceconf

	iphoneencodegui.log( "Encoding file")
	cmd="\""+GLOBALPARAM['mencoder']+"\" "+GLOBALPARAM['SHORT']+" -include "+"\""+GLOBALPARAM['PATHDEF']+"iphoneencode.conf\" -msglevel identify=6 -profile "+fp['DEVICECONF']+" -of avi "+fp['subcmd']+" "+ fp['FPSCMD']+" "+GLOBALPARAM['USERPARAM']+" -o \""+fp['TMP']+"iphoneencode.avi\" \""+fp['path']+"\""
	if externalcall(cmd,'mencoder',progressmsg="Encoding file"):
		return True

	iphoneencodegui.log( "Put in m4v")
	cmd="\""+GLOBALPARAM['mencoder']+"\" -include \""+GLOBALPARAM['PATHDEF']+"iphoneencode.conf\" -msglevel identify=6 -profile ipadcopy "+GLOBALPARAM['USERPARAM']+" -o \""+fp['TMP']+"iphoneencode.m4v\" \""+fp['TMP']+"iphoneencode.avi\""
	return externalcall(cmd, 'mencoder',progressmsg="Put in m4v")


def addsub(fp):
	if fp['subfile'] == "":
		return

	iphoneencodegui.log( "Adding subtitle")
	cmd="\""+GLOBALPARAM['MP4Box']+"\" -add \""+fp['subfile']+":lang=fra\" \""+fp['TMP']+"iphoneencode.m4v\" -out \""+fp['TMP']+"iphoneencodesub.m4v\""
	if externalcall(cmd,'MP4Box',progressmsg="Adding subtitle"):
		return True
	shutil.move(fp['TMP']+"iphoneencodesub.m4v", fp['TMP']+"iphoneencode.m4v")


def addtag(fp):
	temploc=GLOBALPARAM['TMP']+fp['noext']+".m4v"
	shutil.move(fp['TMP']+"iphoneencode.m4v", temploc)
	if GLOBALPARAM['NOTAG']:
		return False
	iphoneencodegui.log( "Tag m4v")
	getvideoinfo(fp,temploc)
	HD=fp['width'] > 1000
	if autotagshows.autotagfile(temploc,GLOBALPARAM['VERBOSE'],fp['dir'],HD,GLOBALPARAM['TMP'],logcbk=iphoneencodegui.log):
		iphoneencodegui.log("ID cannot be found")
		if GLOBALPARAM['INTERACT']:
			line=iphoneencodegui.askIDtoUser(fp['name'])
		else:
			line=""
		autotagshows.autotagfile(temploc,GLOBALPARAM['VERBOSE'],fp['dir'],HD,GLOBALPARAM['TMP'],line,logcbk=iphoneencodegui.log)
	return False

def movingfile(fp):
	iphoneencodegui.log( "Moving file")
	try:
		iphoneencodegui.log( GLOBALPARAM['TMP']+fp['noext']+".m4v "+fp['dest'])
		shutil.move(GLOBALPARAM['TMP']+fp['noext']+".m4v", fp['dest'])
		if fp['dest'] != fp['finaldest']: 
			shutil.move(fp['dest'],fp['finaldest'])
	except Exception, e:
		iphoneencodegui.log("Error moving the file!, trying to move it in the same folder than source \n"+str(e),True)
		fp['dest']=fp['dir']+"/"+fp['noext']+".m4v"
		try:
			shutil.move(GLOBALPARAM['TMP']+fp['noext']+".m4v", fp['dest'])
		except Exception, e:
			iphoneencodegui.log("There is really an issue, cannot move it there too!!! \n"+str(e),True)
		return True

	return False

def processfile(fp):	
	setfilevar(fp)

	if GLOBALPARAM['VERBOSE']:
			iphoneencodegui.log(fp)
	if encodefile(fp):
		return True
	if addsub(fp):
		return True
	if addtag(fp):
		return True
	return movingfile(fp)

def transcodefile(file,fileparamgui={}): 
	iphoneencodegui.log( "Transcoding " + file)
	fp=initfileparam(file)
	if fileparamgui != {}:
		fp['DESTDIR']=fileparamgui['dest']
		fp['FINALDIR']=fileparamgui['destfinal']
		fp['DEVICECONFS']=fileparamgui['deviceconfs']

	m=fp['DEVICECONFS']
	if m == 1:
		fp['DEVICECONFS']=[ "ipad" ]
	elif m == 2:
		fp['DEVICECONFS']=[ "iphone" ]
	else:
		fp['DEVICECONFS']=[ "ipad", "iphone" ]

	error=False
	for fp['DEVICECONF'] in fp['DEVICECONFS']:
		error=processfile(fp)
		if error:
			break

	if error:
		iphoneencodegui.log( file+" not done due to error!",True)
	else:
		iphoneencodegui.log( file+" done!")
		

def cleantempfile():
	if not GLOBALPARAM['VERBOSE']:
		shutil.rmtree(GLOBALPARAM['TMP'])
	
def main(argv):
	globalparamdef()

	filestotranscode=analyzearg(argv)

	if GLOBALPARAM['NOGUI']:
		iphoneencodegui.log( "Transcoding " + " ".join(filestotranscode))
		for file in filestotranscode:
			transcodefile(file)
		cleantempfile()
	else:
		iphoneencodegui.launchGUI("iphonencode "+GLOBALPARAM['version'],filestotranscode,transcodefile,cleantempfile,getGlobalParam)

main(sys.argv[1:])
